﻿package src.com.online.rpg
{
	import src.com.online.rpg.input.InputManager;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.utils.getTimer;
	
	
	/*
	* Game
	* ----
	* 
	* Document class for a game
	* Subclassed to implement a game
	*/
	public class Game extends Sprite
	{
		private var _children:Vector.<GameObject>;		// game object list
		
		// timing
		private var _time:uint;	
		private var _frameTime:Number = 1.0 / 30;		// 30fps
		private var _frameAccumulator:Number = 0;
		private var _turbo:Number = 1.0;
		
		public function get gameWidth():Number		{ return stage.stageWidth; }
		public function get gameHeight():Number		{ return stage.stageHeight; }
		
		public function get turbo():Number			{ return _turbo; }
		public function set turbo(n:Number):void	{ _turbo = n; }
		
		public function Game() 
		{			
			// wait to initialize until we have a valid stage
			if (stage) initialize();
			else addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
		}
		
		private function onAddedToStage(e:Event):void
		{
			removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
			initialize();
		}
		
		public function initialize():void
		{
			_children = new Vector.<GameObject>;
			
			InputManager.initialize(stage);						// create all keyboard listeners
			addEventListener(Event.ENTER_FRAME, onEnterFrame);
			
			_time = getTimer();
		}
		
		// game object creation
		protected function addObject(object:GameObject):void
		{
			_children.push(object);
			addChild(object.graphics);
		}
		
		// game object deletion
		protected function removeObject(object:GameObject):void
		{
			// Remove object from children array
			var i:int = _children.indexOf(object);
			if (i >= 0)
			{
				removeChild(object.graphics);
				_children.splice(i, 1);
			}
		}
		
		// sort all objects based on depth
		protected function depthSort():void
		{
			_children.sort(depthCompare);
			
			// set child index to sorted position
			var shift:uint = numChildren - _children.length;
			for (var i:uint = 0; i < _children.length; i++)
				setChildIndex(_children[i].graphics, i + shift );
		}
		
		private function depthCompare(a:GameObject, b:GameObject):int
		{
			if (a.depth < b.depth) return -1;
			if (a.depth > b.depth) return 1;
			return 0;
		}
		
		private function onEnterFrame(e:Event):void
		{
			var newTime:uint = getTimer();
			var dt:Number = (newTime - _time) / 1000;
			_time = newTime;
			
			_frameAccumulator += dt;
			// have we accumulated enough time for the next frame?
			while (_frameAccumulator >= _frameTime)
			{
				update(_frameTime * _turbo);		// tick the game
				depthSort();
				_frameAccumulator -= _frameTime;
			}
		}
		
		// Game tick
		// Overridden in sub classes
		public function update(dt:Number):void
		{
			// update all game objects
			for each(var child:GameObject in _children)
			{
				child.update(dt);
			}
		}
		
	}
	
}